# encoding: UTF-8

"""
本文件中包含了CTA模块中用到的一些基础设置、类和常量等。
"""

# 把当前根目录添加到python环境变量中
import sys
from itertools import product

import pandas as pd

from const_struct.constant import *

sys.path.append('..')

# 趋势类型
TREND_UP = 1
TREND_DOWN = -1
TREND_NONE = 0
# 某根K线所处位置分类
TREND_POSITION_BALANCE_START = 0b001000000  # 均衡状态开始
TREND_POSITION_BALANCE_OK = 0b010000000  # 均衡状态确认
TREND_POSITION_BALANCE = 0b011000000  # 均衡状态持续
TREND_POSITION_BALANCE_END = 0b111000000  # 均衡状态结束
TREND_POSITION_UP_START = 0b000001000  # 上涨开始
TREND_POSITION_UP_OK = 0b000010000  # 上涨确认
TREND_POSITION_UP = 0b000011000  # 上涨持续
TREND_POSITION_UP_END = 0b000111000  # 上涨结束
TREND_POSITION_DOWN_START = 0b000000001  # 下跌开始
TREND_POSITION_DOWN_OK = 0b000000010  # 下跌确认
TREND_POSITION_DOWN = 0b000000011  # 下跌持续
TREND_POSITION_DOWN_END = 0b000000111  # 下跌结束
TREND_POSITION_NONE = 0b000000000  # 未知


class TREND_POSITION():
    def __init__(self):
        self.balance = 0  # 均衡状态
        self.up = 0  # 上涨
        self.down = 0  # 下跌
        self.balanceStart = 0  # 均衡状态开始
        self.upStart = 0  # 上涨开始
        self.downStart = 0  # 下跌开始
        self.balanceOK = 0  # 均衡状态确认
        self.upOK = 0  # 上涨确认
        self.downOK = 0  # 下跌确认
        self.balanceEnd = 0  # 均衡状态结束
        self.upEnd = 0  # 上涨结束
        self.downEnd = 0  # 下跌结束


# 交易统计结果英汉字典
EN_ZH_DICT = {'totalPeriods': '周期数',
              'holdingPeriods': '持仓周期数',
              'totalCount': '总交易次数',
              'totalWinCount': '总盈利次数',
              'totalLossCount': '总亏损次数',
              'totalInvest': '总投资',
              'winInvest': '盈利投资',
              'lossInvest': '亏损投资',
              'totalProfit': '总利润',  # totalWin - totalLoss
              'totalWin': '总盈利',
              'totalLoss': '总亏损',
              'totalProfitRate': '总利润率',  # totalProfit/totalInvest
              'totalWinProfitRate': '总盈利率',  # totalWin/winInvest
              'totalLossProfitRate': '总亏损率',  # totalLoss/lossInvest
              'perProfit': '平均每笔利润',  # totalProfit/totalCount
              'perProfitRate': '平均每笔利润率',  # totalProfitRate/totalCount
              'maxDrawback': '最大回撤',
              'perWin': '平均每笔盈利',  # totalWin/totalWinCount
              'perFee': '平均每笔佣金',  # totalFee/totalCount
              'perLoss': '平均每笔亏损',  # totalLoss/totalLossCount
              'winRatio': '胜率',  # totalWinCount/totalCount
              'winLossRatio': '盈亏比',  # totalWin/totalLoss
              'annualRate': '年化收益率',
              'annualTradeTimes': '年均交易次数',  # totalLoss/lossInvest
              'maxWin': '最大盈利',
              'maxLoss': '最大亏损',
              'winLastTimes': '最大连续盈利次数',
              'lossLastTimes': '最大连续亏损次数',
              'longCount': '多头交易次数',
              'longWinCount': '多头盈利次数',
              'longLossCount': '多头亏损次数',
              'longProfit': '多头利润',
              'longWin': '多头盈利',
              'longLoss': '多头亏损',
              'longProfitRate': '多头利润率',
              'longWinProfitRate': '多头盈利率',
              'longLossProfitRate': '多头亏损率',
              'perLongProfit': '多头平均每笔利润',
              'perLongProfitRate': '多头平均每笔利润率',
              'maxLongDrawback': '多头最大回撤',
              'perLongWin': '平均多头每笔盈利',
              'perLongFee': '多头平均每笔佣金',
              'perLongLoss': '多头平均每笔亏损',
              'winLongRatio': '多头胜率',
              'winLongLossRatio': '多头盈亏比',
              'annualLongRate': '多头年化收益率',
              'annualLongTimes': '多头年均交易次数',
              'maxLongWin': '多头最大盈利',
              'maxLongLoss': '多头最大亏损',
              'winLongLastTimes': '多头最大连续盈利次数',
              'lossLongLastTimes': '多头最大连续亏损次数',
              'shortCount': '空头交易次数',
              'shortWinCount': '空头盈利次数',
              'shortLossCount': '空头亏损次数',
              'shortProfit': '空头利润',
              'shortWin': '空头盈利',
              'shortLoss': '空头亏损',
              'shortProfitRate': '空头利润率',
              'shortWinProfitRate': '空头盈利率',
              'shortLossProfitRate': '空头亏损率',
              'perShortProfit': '空头平均每笔利润',
              'perShortProfitRate': '空头平均每笔利润率',
              'maxShortDrawback': '空头最大回撤',
              'perShortWin': '平均空头每笔盈利',
              'perShortFee': '空头平均每笔佣金',
              'perShortLoss': '空头平均每笔亏损',
              'winShortRatio': '空头胜率',
              'winShortLossRatio': '空头盈亏比',
              'annualShortRate': '空头年化收益率',
              'annualShortTimes': '空头年均交易次数',
              'maxShortWin': '空头最大盈利',
              'maxShortLoss': '空头最大亏损',
              'winShortLastTimes': '空头最大连续盈利次数',
              'lossShortLastTimes': '空头最大连续亏损次数'

              }
# 策略或指标用周期类型
PERIOD_TYPE_TICK = 0
PERIOD_TYPE_M1 = 1 * 60
PERIOD_TYPE_M3 = 3 * 60
PERIOD_TYPE_M5 = 5 * 60
PERIOD_TYPE_M10 = 10 * 60
PERIOD_TYPE_M15 = 15 * 60
PERIOD_TYPE_M30 = 30 * 60
PERIOD_TYPE_H1 = 60 * 60
PERIOD_TYPE_DAY = 60 * 60 * 24
PERIOD_TYPE_WEEK = 7 * 24 * 60 * 60
PERIOD_TYPE_MONTH = 60 * 60 * 24 * 30
PERIOD_TYPE_YEAR = 60 * 60 * 24 * 365

period_en_zh_dict = {
    "TICK": "分时",
    "M1": "1分钟",
    "M3": "3分钟",
    "M5": "5分钟",
    "M10": "10分钟",
    "M15": "15分钟",
    "M30": "30分钟",
    "H1": "1小时",
    "DAY": "日",
    "WEEK": "周",
    "MONTH": "月",
    "YEAR": "年"
}
period_zh_en_dict = {v: k for k, v in period_en_zh_dict.items()}
period_en_value_dict = {
    "TICK": PERIOD_TYPE_TICK,
    "M1": PERIOD_TYPE_M1,
    "M3": PERIOD_TYPE_M3,
    "M5": PERIOD_TYPE_M5,
    "M10": PERIOD_TYPE_M10,
    "M15": PERIOD_TYPE_M15,
    "M30": PERIOD_TYPE_M30,
    "H1": PERIOD_TYPE_H1,
    "DAY": PERIOD_TYPE_DAY,
    "WEEK": PERIOD_TYPE_WEEK,
    "MONTH": PERIOD_TYPE_MONTH,
    "YEAR": PERIOD_TYPE_YEAR
}
period_zh_value_dict = {k: period_en_value_dict[v] for k, v in period_zh_en_dict.items()}


class TypePeriod:
    TICK = 0
    M1 = 1 * 60
    M3 = 3 * 60
    M5 = 5 * 60
    M10 = 10 * 60
    M15 = 15 * 60
    M30 = 30 * 60
    H1 = 60 * 60
    DAY = 60 * 24 * 60
    WEEK = 60 * 24 * 7 * 60
    MONTH = 60 * 24 * 30 * 60
    YEAR = 60 * 24 * 365 * 60


# 常量定义
# CTA引擎中涉及到的交易方向类型
STRATEGY_ORDER_NONE = 'UN'
STRATEGY_ORDER_BUY = '买开'  # 开多
STRATEGY_ORDER_SELL = '卖平'  # 平多
STRATEGY_ORDER_SHORT = '卖开'  # 开空
STRATEGY_ORDER_COVER = '买平'  # 平空
STRATEGY_ORDER_COVER_BUY = '平空开多'
STRATEGY_ORDER_SELL_SHORT = '平多开空'
strategy_order_type = {
    STRATEGY_ORDER_BUY: 1,
    STRATEGY_ORDER_SELL: -1,
    STRATEGY_ORDER_SHORT: -2,
    STRATEGY_ORDER_COVER: 2,
    STRATEGY_ORDER_COVER_BUY: 4,
    STRATEGY_ORDER_SELL_SHORT: -4
}


class StraOrderType:
    BUY = 1
    SELL = -1
    SHORT = -2
    COVER = 2
    COVER_BUY = 4
    SELL_SHORT = -4


class StraOffsetType:
    OPEN = 1
    CLOSE = -1
    STOP_LOSS = -2
    STOP_WIN = 2


class StraDirectionType:
    LONG = 1
    SHORT = -1


class StraOrderTypeCn:
    BUY = '开多'
    SELL = '平多'
    SHORT = '开空'
    COVER = '平空'
    COVER_BUY = '平空开多'
    SELL_SHORT = '平多开空'


class StraOffsetTypeCn:
    OPEN = '开'
    CLOSE = '平'
    STOP_LOSS = '止损'
    STOP_WIN = '止赢'


class StraDirectionTypeCn:
    LONG = '多'
    SHORT = '空'


STRATEGY_SIGNAL_OFFSET_NONE = 'UN'
STRATEGY_SIGNAL_OFFSET_OPEN = '开'
STRATEGY_SIGNAL_OFFSET_CLOSE = '平'
STRATEGY_SIGNAL_OFFSET_STOPLOSS = '止损'
STRATEGY_SIGNAL_DIRECTION_LONG = '多'
STRATEGY_SIGNAL_DIRECTION_SHORT = '空'
STRATEGY_SIGNAL_DIRECTION_NONE = 'UN'
stra_bssc_zh_zh_dict = {}
# 本地停止单状态
STOPORDER_WAITING = '等待中'
STOPORDER_CANCELLED = '已撤销'
STOPORDER_TRIGGERED = '已触发'

# 本地停止单前缀
STOPORDERPREFIX = 'CtaStopOrder.'

# 数据库名称
DBTYPE_SQLITE = 'SQLITE'
DBTYPE_MONGODB = 'MONGODB'
SETTING_DB_NAME = 'Trader_Setting_Db'
TICK_DB_NAME = 'Trader_Tick_Db'
DAILY_DB_NAME = 'Trader_Daily_Db'
MINUTE_DB_NAME = 'CTP_Min_Db'
STRATEGY_DB_NAME = 'Strategy_Db'
STRATEGY_TEST_DB_NAME = 'Strategy_Test_Db'
STRATEGY_TEST_ORDER_TABLE_NAME = 'Strategy_Test_'  # 策略测试结果表，后跟策略名称
STRATEGY_TABLE_NAME = 'Strategies'
STRATEGY_PARAMS_DB_NAME = 'Strategy_Db'

SQLITEDB_STRATEGY_NAME = 'strategtDB'
SQLITEDB_HISTORY_NAME = 'quoteDB'

# 引擎类型，用于区分当前策略的运行环境
ENGINETYPE_BACKTESTING = 'backtesting'  # 回测
ENGINETYPE_TESTING = 'testing'  # 测试 在实盘环境中跑，但不与实际账户连接,只记录交易信号
ENGINETYPE_TRADING = 'trading'  # 实盘
ENGINETYPE_QUOTE = 'quote'
ENGINETYPE_MARKET = 'market'
ENGINETYPE_RISK = 'RISK'
ENGINETYPE_DATA = 'DATA'
ENGINETYPE_ACCOUNT = 'ACCOUNT'

HOLDING_TYPE = {'NONE': 0,
                'SINGLE': 1,
                'DOUBLE': 2,
                'LONG': 3,
                'SHORT': 4}
HOLDING_TYPE_NONE = 'NONE'
HOLDING_TYPE_SINGLE = 'SINGLE'
HOLDING_TYPE_DOUBLE = 'DOUBLE'
HOLDING_TYPE_LONG = 'LONG'
HOLDING_TYPE_SHORT = 'SHORT'

# 指标类型
INDICATOR_TYPE = {
    'TREND': 1,  # 趋势型
    'INV': 2,  # 反转型
    'TRACE': 3  # 轨道型
}
INDICATOR_TYPE_TREND = "TREND"
INDICATOR_TYPE_INV = "INV"
INDICATOR_TYPE_TRACE = "TRACE"

# 变量输出类型
VARIABLE_OUT_TYPE = {
    "None": 0,  # 不输出
    "Main": 1,  # 主坐标轴
    "Second": 2,  # 副坐标轴
    "Window": 3  # 由窗口的大小确定
}
VARIABLE_OUT_TYPE_NONE = "None"
VARIABLE_OUT_TYPE_MAIN = "Main"
VARIABLE_OUT_TYPE_SECOND = "Second"
VARIABLE_OUT_TYPE_WINDOW = "Window"

# 公式类型：指标、策略
FORMULA_TYPE_STRATEGY = 'strategy'  # 交易策略
FORMULA_TYPE_INDICATOR = 'indicator'  # 指标
FORMULA_TYPE_SELECTOR = 'selector'  # 选股方法

# CTA引擎中涉及的数据类定义


KDataFrame = pd.DataFrame(columns=['open', 'high', 'low', 'close', 'vol', 'amt', 'datetime'])


class StopOrder(object):
    """本地停止单"""

    def __init__(self):
        """Constructor"""
        self.vtSymbol = EMPTY_STRING
        self.orderType = EMPTY_UNICODE
        self.direction = EMPTY_UNICODE
        self.offset = EMPTY_UNICODE
        self.price = EMPTY_FLOAT
        self.volume = EMPTY_INT

        self.strategy = None  # 下停止单的策略对象
        self.stopOrderID = EMPTY_STRING  # 停止单的本地编号 
        self.status = EMPTY_STRING  # 停止单状态


class KData(object):
    def __init__(self, data=None):
        """
        利用字典初始化KData
        :param data: 包含关键字为['datetime','open','high','low','close',volume']的字典
        """
        if data is None:
            self.datetime = None
            self.open = 0.0
            self.high = 0.0
            self.low = 0.0
            self.close = 0.0
            self.vol = 0
            self.amt = 0.0
        else:
            self.datetime = data['datetime']
            self.open = data['open']
            self.high = data['high']
            self.low = data['low']
            self.close = data['close']
            self.vol = data['vol']
            self.amt = data['amt']


class KLine(pd.DataFrame):
    """K线
    index：datetime,
    open,high,low,close,volume
    period
    """

    def __init__(self, period=1, data=None):
        super(KLine, self).__init__()
        self.period = period
        if data is not None:
            self.index = data.index
            self.open = data['open']
            self.high = data['high']
            self.low = data['low']
            self.close = data['close']
            self.volume = data['volume']


class CtaBarData(object):
    """K线数据"""

    def __init__(self):
        """Constructor"""
        self.vtSymbol = EMPTY_STRING  # vt系统代码
        self.symbol = EMPTY_STRING  # 代码
        self.exchange = EMPTY_STRING  # 交易所

        self.open = EMPTY_FLOAT  # OHLC
        self.high = EMPTY_FLOAT
        self.low = EMPTY_FLOAT
        self.close = EMPTY_FLOAT

        self.date = EMPTY_STRING  # bar开始的时间，日期
        self.time = EMPTY_STRING  # 时间
        self.datetime = None  # python的datetime时间对象

        self.volume = EMPTY_INT  # 成交量
        self.openInterest = EMPTY_INT  # 持仓量
        self.period = 1  # K线周期


class BarData(object):
    """K线数据"""

    def __init__(self):
        """Constructor"""
        self.symbol = EMPTY_STRING  # 代码
        self.exchange = EMPTY_STRING  # 交易所

        self.open = EMPTY_FLOAT  # OHLC
        self.high = EMPTY_FLOAT
        self.low = EMPTY_FLOAT
        self.close = EMPTY_FLOAT

        self.date = EMPTY_STRING  # bar开始的时间，日期
        self.time = EMPTY_STRING  # 时间
        self.datetime = None  # python的datetime时间对象

        self.volume = EMPTY_INT  # 成交量
        self.openInterest = EMPTY_INT  # 持仓量
        self.period = 1  # K线周期


class TickData(object):
    """Tick数据"""

    def __init__(self):
        """Constructor"""
        self.instrument_id = EMPTY_STRING  # 代码
        self.symbol = EMPTY_STRING  # 合约代码
        self.exchange = EMPTY_STRING  # 交易所代码

        # 成交数据
        self.lastPrice = EMPTY_FLOAT  # 最新成交价
        self.volume = EMPTY_INT  # 最新成交量
        self.openInterest = EMPTY_INT  # 持仓量
        self.amount = EMPTY_FLOAT

        self.upperLimit = EMPTY_FLOAT  # 涨停价
        self.lowerLimit = EMPTY_FLOAT  # 跌停价

        # tick的时间
        self.date = EMPTY_STRING  # 日期
        self.time = EMPTY_STRING  # 时间
        self.datetime = None  # python的datetime时间对象

        # 五档行情
        self.bidPrice1 = EMPTY_FLOAT
        self.bidPrice2 = EMPTY_FLOAT
        self.bidPrice3 = EMPTY_FLOAT
        self.bidPrice4 = EMPTY_FLOAT
        self.bidPrice5 = EMPTY_FLOAT

        self.askPrice1 = EMPTY_FLOAT
        self.askPrice2 = EMPTY_FLOAT
        self.askPrice3 = EMPTY_FLOAT
        self.askPrice4 = EMPTY_FLOAT
        self.askPrice5 = EMPTY_FLOAT

        self.bidVolume1 = EMPTY_INT
        self.bidVolume2 = EMPTY_INT
        self.bidVolume3 = EMPTY_INT
        self.bidVolume4 = EMPTY_INT
        self.bidVolume5 = EMPTY_INT

        self.askVolume1 = EMPTY_INT
        self.askVolume2 = EMPTY_INT
        self.askVolume3 = EMPTY_INT
        self.askVolume4 = EMPTY_INT
        self.askVolume5 = EMPTY_INT


class CtaTickData(object):
    """Tick数据"""

    def __init__(self):
        """Constructor"""
        self.vtSymbol = EMPTY_STRING  # vt系统代码
        self.symbol = EMPTY_STRING  # 合约代码
        self.exchange = EMPTY_STRING  # 交易所代码

        # 成交数据
        self.lastPrice = EMPTY_FLOAT  # 最新成交价
        self.volume = EMPTY_INT  # 最新成交量
        self.openInterest = EMPTY_INT  # 持仓量
        self.amount = EMPTY_FLOAT

        self.upperLimit = EMPTY_FLOAT  # 涨停价
        self.lowerLimit = EMPTY_FLOAT  # 跌停价

        # tick的时间
        self.date = EMPTY_STRING  # 日期
        self.time = EMPTY_STRING  # 时间
        self.datetime = None  # python的datetime时间对象

        # 五档行情
        self.bidPrice1 = EMPTY_FLOAT
        self.bidPrice2 = EMPTY_FLOAT
        self.bidPrice3 = EMPTY_FLOAT
        self.bidPrice4 = EMPTY_FLOAT
        self.bidPrice5 = EMPTY_FLOAT

        self.askPrice1 = EMPTY_FLOAT
        self.askPrice2 = EMPTY_FLOAT
        self.askPrice3 = EMPTY_FLOAT
        self.askPrice4 = EMPTY_FLOAT
        self.askPrice5 = EMPTY_FLOAT

        self.bidVolume1 = EMPTY_INT
        self.bidVolume2 = EMPTY_INT
        self.bidVolume3 = EMPTY_INT
        self.bidVolume4 = EMPTY_INT
        self.bidVolume5 = EMPTY_INT

        self.askVolume1 = EMPTY_INT
        self.askVolume2 = EMPTY_INT
        self.askVolume3 = EMPTY_INT
        self.askVolume4 = EMPTY_INT
        self.askVolume5 = EMPTY_INT


class StrategyParamData(object):
    def __init__(self):
        self.name = EMPTY_STRING  # 参数名称
        self.min = EMPTY_INT  # 参数最小值
        self.max = EMPTY_INT  # 参数最大值
        self.step = EMPTY_INT  # 参数优化时步长
        self.multiplier = 1  # 参数乘数，当该字段不为1时，在具体应用中参数值要除以该字段，它的存在是为了保证参数为整数
        self.description = EMPTY_STRING  # 参数说明
        self.default = EMPTY_INT  # 参数缺省值，可能是最优值


class StraParam(object):
    """策略参数"""

    def __init__(self, param=None):
        self._id = EMPTY_STRING  # 参数代码
        self.name = EMPTY_STRING  # 参数名称
        self.min = EMPTY_INT  # 参数最小值
        self.max = EMPTY_INT  # 参数最大值
        self.step = EMPTY_INT  # 参数优化时步长
        self.multiplier = 1  # 参数乘数，当该字段不为1时，在具体应用中参数值要除以该字段，它的存在是为了保证参数为整数
        self.description = EMPTY_STRING  # 参数说明
        self.default = EMPTY_INT  # 参数缺省值，可能是最优值

        self.symbol = EMPTY_STRING  # 当用于实盘时，适用的标的
        self.period = EMPTY_INT  # 当用于实盘时，最优周期，与其对应的值是default

        if param:
            d = self.__dict__
            for k, v in param:
                if k in d.keys():
                    d[k] = v


class StrategyVariable(object):
    """策略变量"""

    def __init__(self):
        self.name = EMPTY_STRING  # 变量名称
        self.value = EMPTY_INT
        self.out_type = VARIABLE_OUT_TYPE_NONE


class StraSetting(object):
    def __init__(self, params=None, symbol='', pkg='', name='', class_name='', period=0, strategy_type='',
                 description='', data_len=0, days=10, used=0, sd='', ed=''):
        self.params = params
        self.symbol = symbol
        self.pkg = pkg  # 策略类所在的包名称，是一完整路径，如：boxquant.strategy.trend_strategy
        self.name = name  # 策略实例名称
        self.class_name = class_name  # 策略类名称
        self.period = period
        self.strategy_type = strategy_type
        self.description = description
        self.data_len = data_len
        self.days = days
        self.sd = sd
        self.ed = ed
        self.used = used
        self.other_data = None  # {symbol:symbol,period:period,sd:start_datetime,ed:end_datetime,dlen:data_len}
        self.instances = None


class StrategySignal(object):
    """策略信号"""

    def __init__(self):
        self.name = EMPTY_STRING  # strategy instance name
        self.params = None
        self.symbol = EMPTY_STRING
        self.oc_flag = STRATEGY_SIGNAL_OFFSET_NONE
        self.ls_flag = STRATEGY_SIGNAL_DIRECTION_NONE
        self.bssc = 0  # 0: money, 1: buy, -1: sell, -2: short, 2: cover, 4: cover and buy, -4: sell and short
        self.datetime = None  # 策略信号时间 2010-01-10 hh:mm:ss
        self.price = EMPTY_FLOAT
        self.vol = EMPTY_FLOAT  # >1: 为手数，<1 and >0:可用手数的百分比，<0:无效
        self.stop_price = EMPTY_FLOAT
        self.order_type = STRATEGY_ORDER_NONE


class TradingResult(object):
    """每笔交易的结果"""

    def __init__(self, entryPrice, entryDt, exitPrice,
                 exitDt, volume, rate, slippage, size, tradeDirection=DIRECTION_LONG):
        """Constructor"""
        self.tradeDirection = tradeDirection
        self.entryPrice = entryPrice  # 开仓价格
        self.exitPrice = exitPrice  # 平仓价格

        self.entryDt = entryDt  # 开仓时间datetime
        self.exitDt = exitDt  # 平仓时间

        self.vol = volume  # 交易数量（+/-代表方向）

        self.turnover = (self.entryPrice + self.exitPrice) * size * abs(volume)  # 成交金额
        if rate < 1:
            self.commission = self.turnover * rate  # 手续费成本
        else:
            self.commission = abs(volume) * rate
        self.slippage = slippage * 2 * size * abs(volume)  # 滑点成本
        self.pnl = ((self.exitPrice - self.entryPrice) * volume * size
                    - self.commission - self.slippage)  # 净盈亏


class OptimizationSetting(object):
    """优化设置"""

    def __init__(self):
        """Constructor"""
        self.param_dict = {}
        self.param_setting = []

        self.optimize_target = ''  # 优化目标字段

    def add_parameter(self, name, start, end=None, step=None):
        """增加优化参数"""
        if end is None and step is None:
            self.param_dict[name] = [start]
            return

        if end <= start:
            print('参数起始点必须小于终止点')
            return

        if step <= 0:
            print('参数步进必须大于0')
            return

        l = []
        param = start

        while param <= end:
            l.append(param)
            param += step

        self.param_dict[name] = l

    def generate_setting(self):
        """生成优化参数组合"""
        # 参数名的列表
        nameList = list(self.param_dict.keys())
        paramList = list(self.param_dict.values())

        # 使用迭代工具生产参数对组合
        productList = list(product(*paramList))

        # 把参数对组合打包到一个个字典组成的列表中
        settingList = []
        for p in productList:
            d = dict(list(zip(nameList, p)))
            settingList.append(d)
        self.param_setting = settingList
        return settingList

    def setOptimizeTarget(self, target):
        """设置优化目标字段"""
        self.optimize_target = target
        self.lperiod = EMPTY_INT


def format_number(n, max_decimals=2, delimeter=''):
    """格式化数字到字符串"""
    n = round(n, max_decimals)  # 保留两位小数
    return format(n, delimeter)  # 加上千分符


if __name__ == '__main__':
    a = OptimizationSetting()
    a.add_parameter('p1', 1, 3, 1)
    a.add_parameter('p2', 2, 4, 1)
    a.add_parameter('p3', 3, 5, 1)
    b = a.generate_setting()
    print(a.param_setting)
    print(b)
    print(StraOrderType.SELL_SHORT)

    print(format_number(1234.5345))
